<?php
namespace soa\partner;

use artisan\cache;
use artisan\http;
use soa\client;
use soa\common\RemoteDB;
use soa\parter\sto\mobileAddress;
use soa\partner\ane\BaseInformation;
use soa\partner\kj\KjClient;
use soa\partner\zt\ztCommon;

class DeliveryCommon extends client
{
    public $isPda = 0;

    /**
     * @var string
     */
    public $service_url = 'http://pda.core.kuaidihelp.com';

    /**
     * @var string
     */
    public $service_name = 'kuaidihelp_pda';

    /**
     * http 请求超时时间
     *
     * @var int
     */
    protected $_timeout = 20;

    private $brand;

    public function __construct()
    {
        if(!\soa\check\EnvCheck::isEnvOnline()){
            $this->isPda = 1;
        }
        //暂时
        if(empty($this->isPda)){
            $this->service_url = 'http://express.core.kuaidihelp.com';
            $this->service_name = 'kuaidihelp_express';
        }
    }

    /**
     * 派件列表批量获取提示信息
     *
     * @return array|string
     */
    public function getNotice($data)
    {
        if(empty($data) || !is_array($data)){
            return false;
        }

        $result = $this->post($this->isPda ? '/v1/deliveryList/DeliveryPlus/getNotice' : '/v1/express/reflush/getNotice',
            array(
                'cmPhone'     => $data['cmPhone'],
                'waybillNos'  => $data['waybillNos'],
                'empNo'       => $data['empNo'],
                'brand'       => $data['brand'],
                'date'        => $data['date'],
                'cmId'        => $data['cmId'],
                'versionCode' => $data['versionCode'],
        ));

        return $result;
    }

    /**
     * 单个运单号获取提示信息
     *
     * @return array|string
     */
    public function getDetailNotice($data)
    {
        if(empty($data) || !is_array($data)){
            return false;
        }

        $result = $this->post($this->isPda ? '/v1/deliveryList/DeliveryPlus/getDetailsNotice' : '/v1/express/reflush/getDetailsNotice', array(
            'cmPhone'     => $data['cmPhone'],
            'waybillNo'   => $data['waybillNo'],
            'empNo'       => $data['empNo'],
            'cmId'        => $data['cmId'],
            'brand'       => $data['brand'],
            'versionCode' => $data['versionCode'],
            'type'        => !empty($data['type'])?$data['type']:'',//  多个type用英文逗号分隔。type类型：'notes', 'message', 'liuyan', 'intercept', 'pay', 'tousu', 'complain','weight','zbTask','noArrive','msgStatus','mistake'
        ));

        return $result;
    }

    /**
     * 更新派件列表提示信息的缓存
     *
     * @param $data
     * @param array $option
     * @return mixed
     */
    public function updateNotice($data, $option = [])
    {
        return $this->updateDeliveryPlus('updateNotice', $data, $option);
    }

    /**
     * 修改派件列表运单号状态
     *
     * @return array|string
     */
    public function handle($waybillDatas,$scanInfo,$status)
    {
        $brand = !empty($scanInfo['brand']) ? $scanInfo['brand'] : '';

        if(empty($waybillDatas) || !in_array($brand,['sto','zt','ane','zbao']) || empty($status) ||
            ('zbao' == $brand && empty($scanInfo['cm_phone'])) ||
            ('zbao' != $brand && empty($scanInfo['emp_no']))
        )
        {
            return false;
        }

        $this->setTimeout(5);
        $result = $this->post($this->isPda ? '/v1/deliveryList/Delivery/handle' : '/v1/express/Delivery/handle',
            array(
                'waybillDatas' => $waybillDatas,
                'scanInfo'     => $scanInfo,
                'status'       => $status,
                'brand'        => $brand,
            ));

        return $result;
    }

    /**
     * 众包快递员：派件列表-签收详情
     *
     * @return array|string
     */
    public function zbDelivery($cmInfo,$taskId,$type)
    {
        if(empty($cmInfo) || empty($type)){
            return false;
        }

        $result = $this->post($this->isPda ? '/v1/deliveryList/Delivery/getZbDelivery' : '/v1/express/Delivery/getZbDelivery',array(
            'cmInfo' => $cmInfo,
            'taskId' => $taskId,
            'type' => $type,
        ));

        return $result;
    }

    /**
     * 根据运单号查询单号的地址、电话、收件人等信息
     *
     * @param $waybillNos
     * @param $cmInfo
     * @param string $type
     * @return array|string
     */
    public function getMobileAddressInfo($waybillNos, $cmInfo, $type = 'address')
    {
        $cmPhone = !empty($cmInfo['username']) ? $cmInfo['username'] : (!empty($cmInfo['cm_phone']) ? $cmInfo['cm_phone'] : '');
        $cmId    = $cmInfo['id'] ?: '';
        $empNo   = $cmInfo['emp_no'] ? : '';
        $this->brand   = $cmInfo['brand'] ? : '';

        if('sto' == $this->brand){
            $obj = new mobileAddress();
            $return = $obj->ast($waybillNos, $cmPhone, $cmId, $empNo, $type);
        } elseif('zt' == $this->brand){
            $obj = new ztCommon();
            $return = $obj->getMobileAddressByWaybillNo($waybillNos, $cmPhone, $cmId, $empNo, $type);
        }elseif('ane' == $this->brand){
            $obj = new \soa\partner\ane\MobileAddress();
            $return = $obj->getMobileAddressByWaybillNo($waybillNos, $cmPhone, $cmId, $empNo, $type);
        }else{
            $return = [];
        }

        return $return;
    }

    /**
     * 问题件列表
     *
     * @param array $cmInfo
     * @return array
     */
    public function getQuestionList($cmInfo = [])
    {
        $brand = $cmInfo['brand'];
        if(!in_array($brand,['sto','zt','ane','kj','qf'])){
            return '暂时不支持您的快递品牌！';
        }

        $key = $brand . ucfirst(__FUNCTION__);
        $return = cache::connect('pda')->get($key);
        if(is_array($return) && $return){
            return $return;
        }

        $return = [];
        if('kj' == $brand){
            $return = (new KjClient())->getQuestionList();
        }elseif('ane' == $brand){
            $return = (new BaseInformation())->getQuestionList();
        }elseif('sto' == $brand){
            foreach($this->stoBadDesc as $k=>$v){
                $return[$k] = [
                    'badWayBillCode' => $k,
                    'badWayBillDesc' => $v,
                ];
            }
        }elseif('zt' == $brand){
            if(empty($cmInfo['username'])){
                $cmInfo = (new RemoteDB('kd_pda', 'tbl_scan_courier_zt'))->getOne(array('switch' => 'on', 'state' => 'approve','key !='=>'0000000000','emp_no !='=>''),'id desc');
            }
            $phone = !empty($cmInfo['username']) ? $cmInfo['username'] : $cmInfo['cm_phone'];
            $ret = (new ztCommon())->ztXMLInterface($phone,['optype'=>'G008'],0);
            if(isset($ret['Success']['d']['p'])) {
                foreach ($ret['Success']['d']['p'] as $v) {
                    $return[$v['a']] = [
                        'badWayBillCode' => $v['a'],
                        'badWayBillDesc' => $v['b'],
                    ];
                }
            }elseif(isset($ret['error']['reason'])){
                $return = $ret['error']['reason'];
            }
        }elseif('qf' == $brand){
            foreach($this->qfBadDesc as $title=>$item){
                $return[] = [
                    'title'          => $title,
                    'badWayBillList' => $item,
                ];
            }
        }

        is_array($return) && $return and cache::connect('pda')->set($key,$return,3600);
        return $return;
    }

    /**
     * @param $brand
     * @param $waybillNos
     * @param int $timeOut
     * @param int $size
     * @param string $cmPhone
     * @return array
     */
    public static function getOperate($brand, $waybillNos, $timeOut = 5, $size = 10, $cmPhone = '')
    {
        $return = [];

        $waybillNoBlocks = array_chunk($waybillNos, $size);
        foreach($waybillNoBlocks as $waybillNoBlock){
            $result = self::getOperateEach($brand, $waybillNoBlock, $timeOut, $cmPhone);
            $return = $return + $result;
        }

        return $return;
    }

    /**
     * @param $brand
     * @param $waybillNos
     * @param int $timeOut
     * @param string $cmPhone
     * @return array
     */
    public static function getOperateEach($brand, $waybillNos, $timeOut = 5, $cmPhone = '')
    {
        $return = [];

        $time1 = time();
        $query = array(
            'company'    => $brand,
            'express_no' => implode(',', $waybillNos),
            'params'     => '["GetOperate"]',
            'channel'    => 'pda-batch'
        );
        $url = 'http://express.interface.kuaidihelp.com/multinfo.php';
        $result = http::get($url, $query, ['TIMEOUT' => $timeOut]);

        $useTime = time() - $time1;
        if ($useTime >= 5) {
            logDebug('multinfo接口超过' . $useTime . 's。运单号：' . json_encode($waybillNos, JSON_UNESCAPED_UNICODE), $brand . '_multinfo_1', $cmPhone);
        } elseif (empty($result)) {
            logDebug('multinfo接口超过接口无返回' . $useTime . 's。运单号：' . json_encode($waybillNos, JSON_UNESCAPED_UNICODE), $brand . '_multinfo_2', $cmPhone);
        }

        if(!empty($result)) {
            $flowResult = json_decode($result, true);
            if(json_last_error() == 0 && isset($flowResult['GetOperate']) && $flowResult['GetOperate'] !== null) { //=== null表示发生网络错误导致未获得流转信息
                //如果是单个单号的，返回结果格式不一致，将其转化为与多个查询相同的格式
                if(count($waybillNos) == 1){
                    $flowResult['GetOperate'] = array(array_pop($waybillNos) => $flowResult['GetOperate']);
                }
                $return = $flowResult['GetOperate'];
            }
        }
        return $return;
    }

    /**
     * @param $brand
     * @param $waybillNos
     * @param int $timeOut
     * @param int $size
     * @param bool $returnNoResult
     * @param string $cmPhone
     * @return array
     */
    public static function bindStatus($brand, $waybillNos, $timeOut = 5, $size = 10, $returnNoResult = true, $cmPhone = '')
    {
        if(empty($waybillNos) || !is_array($waybillNos)) {
            return [];
        }

        $return = [];

        $waybillNoBlocks = array_chunk($waybillNos, $size);

        foreach ($waybillNoBlocks as $waybillNoBlock) {
            $result = self::bindStatusEach($brand, $waybillNoBlock, $timeOut, $returnNoResult, $cmPhone);
            $return = $return + $result;
        }

        return $return;
    }

    /**
     * @param $brand
     * @param $waybillNos
     * @param int $timeOut
     * @param bool $returnNoResult
     * @param string $cmPhone
     * @return array
     */
    public static function bindStatusEach($brand, $waybillNos, $timeOut = 5, $returnNoResult = true, $cmPhone = '')
    {
        $return = [];

        $time1 = time();
        $url = 'http://express.interface.kuaidihelp.com/infor.php';
        $result = http::get($url, [
            'type'       => 'end.status',
            'company'    => $brand,
            'express_no' => implode(',', $waybillNos),
            'channel'    => 'delivery'
        ], ['TIMEOUT' => $timeOut]);

        $useTime = time() - $time1;
        if ($useTime >= 5) {
            logDebug('查运单号最新状态接口超过' . $useTime . 's。运单号：' . json_encode($waybillNos, JSON_UNESCAPED_UNICODE), $brand . '_bind_status_1', $cmPhone);
        } elseif (empty($result)) {
            logDebug('查运单号最新状态接口无返回' . $useTime . 's。运单号：' . json_encode($waybillNos, JSON_UNESCAPED_UNICODE), $brand . '_bind_status_2', $cmPhone);
        }

        if($result) {
            $result = json_decode($result, true);
            if(json_last_error() == 0 && isset($result['status']) && $result['status'] == 'success' && count($result['desc']) > 0) {
                foreach ($result['desc'] as $waybillNo => $item) {
                    if($waybillNo && $item['express_status']){
                        if(stripos($item['express_status'], '签收') !== false) {
                            $return[$waybillNo] = 'sign';
                        } elseif (stripos($item['express_status'], '问题') !== false || stripos($item['express_status'], '疑难') !== false) {
                            $return[$waybillNo] = 'problem';
                        } else {
                            $return[$waybillNo] = 'unknow';
                        }
                    }else{
                        if($returnNoResult){
                            $return[$waybillNo] = 'unknow';
                        }else{
                            $return[$waybillNo] = 'null';
                        }
                    }
                }
            } else {
                if($returnNoResult){
                    foreach ($waybillNos as $item) {
                        $return[$item] = 'unknow';
                    }
                }else{
                    foreach ($waybillNos as $item) {
                        $return[$item] = 'null';
                    }
                }
            }
        }else {
            if($returnNoResult){
                foreach ($waybillNos as $item) {
                    $return[$item] = 'unknow';
                }
            }else{
                foreach ($waybillNos as $item) {
                    $return[$item] = 'null';
                }
            }
        }

        return $return;
    }

    public function updateDelivery($api, $data, $option = [])
    {
        $url = $this->isPda ? 'http://pda.core.kuaidihelp.com/v1/deliveryList/Delivery/' . $api : 'http://express.core.kuaidihelp.com/v1/express/Delivery/'  . $api;
        return http::post($url, $data, $option);
    }

    public function updateDeliveryPlus($api, $data, $option = [])
    {
        $url = $this->isPda ? 'http://pda.core.kuaidihelp.com/v1/deliveryList/DeliveryPlus/' . $api : 'http://express.core.kuaidihelp.com/v1/express/reflush/'  . $api;
        return http::post($url, $data, $option);
    }

    public static function getAddressQueue($brand)
    {
        if(!in_array($brand,['sto','zt','ane'])){
            return '';
        }
        return 'mobile_address_queue_' . $brand;
    }

    public static function logMobileAddress($brand, &$insertData)
    {
        $queueKey = self::getAddressQueue($brand);
        if($queueKey && $insertData){
            return cache::connect('pda')->push($queueKey, json_encode($insertData));
        }
    }

    public static function getDeliveryUserCacheKey($brand)
    {
        if(!in_array($brand,['sto','zt','ane'])){
            return '';
        }
        return 'all_delivery_user_key_all' . $brand;
    }

    public static function getDeliveryUserQueue($brand)
    {
        if(!in_array($brand,['sto','zt','ane'])){
            return '';
        }
        return $brand . '_delivery_user_remind';
    }

    public static function getCODQueue($brand)
    {
        if(!in_array($brand,['sto','zt','ane'])){
            return '';
        }
        return 'pay_on_delivery_queue_' . $brand;
    }

    public static function logCOD($brand, &$insertData)
    {
        $queueKey = self::getCODQueue($brand);
        if($queueKey && $insertData){
            return cache::connect('pda')->push($queueKey, json_encode($insertData));
        }
    }

    public static function getScanCountNoKey($brand, $cmPhone)
    {
        return 'scan_count_' .$brand . '_' . $cmPhone;
    }

    public static function deliKey($brand, $cmCode, $date = '')
    {
        empty($date) and $date = date('Y-m-d');
        return 'PI:'.$brand.':' . $cmCode . ':' . $date;
    }

    public static function getDeliveryListCache($brand, $cmCode, $date = '')
    {
        $list = cache::connect('pda')->hGetAll(self::deliKey($brand, $cmCode, $date));
        return !empty($list) && is_array($list) ? $list : [];
    }

    /**
     * 申通问题件列表
     *
     * @var array
     */
    public $stoBadDesc = [
        '14' => '外包装破损,内件破损,短少,丢失',
        '15' => '外包装完好,内件不符,破损,短少,丢失',
        '16' => '外包装污染',
        '17' => '面单详情与实际内件不符',
        '18' => '地址错误',
        '19' => '电话错误,空号,停机',
        '20' => '面单脱落',
        '21' => '双面单',
        '22' => '有单无货',
        '23' => '收货信息不详',
        '24' => '超派件,客户要求更改地址',
        '25' => '超派件,客户自取',
        '26' => '超派件,转发EMS',
        '27' => '超派件,退回',
        '28' => '天气,自然灾害等原因导致延误',
        '29' => '交通事故导致延误',
        '30' => '突发事件导致延误',
        '31' => '违禁品,机关查扣',
        '32' => '大字错写导致错发',
        '33' => '建包错发件',
        '34' => '送无人,电话联系明日送',
        '35' => '送无人,电话联系不上明日送',
        '36' => '搬家等特殊事件',
        '37' => '节假日延迟派送',
        '38' => '客户要求更改地址,时间送',
        '40' => '客户拒收',
        '41' => '学校自取件',
        '42' => '面单注明自取件',
        '43' => '面单注明自取,客户拒提',
        '44' => '自取件',
        '45' => '客户要求自取',
        '46' => '发件公司要求改地址',
        '47' => '发件公司要求退回',
        '48' => '超派,电话联系不上',
        '49' => '违禁品',
        '50' => '超规格',
        '51' => '无面单已认领',
        '52' => '联系好下午送',
        '53' => '网络错分件',
        '54' => '到付费用问题',
        '55' => '发票问题'
    ];

    /**
     * @var array
     */
    public $qfBadDesc = [
        '中转原因'         => [
            '应到未到件',
            '未赶上中转',
            '错发件',
            '面单脱落',
            '延误件',
            '遗失件',
            '破损件',
            '提货包内短少',
            '留仓件',
            '主干线爆仓',
            '包装破损重装',
            '站点异常',
            '操作结束 班车到达卸货',
            '班车晚点 未赶上中转',
            '破损件',
        ],
        '亚马逊-上门退换(信封)' => [
            '弃件(无货可办、重复退单)',
            '取货完成'
        ],
        '亚马逊—全部拒收'     => [
            '客户取消订单',
            '与客户期望不符',
            '配送超时',
            '商品外包装破损',
            '商品破损(内件)',
            '配错货',
            '商品少配件',
        ],
        '亚马逊—其他'       => [
            '其他'
        ],
        '亚马逊—包裹丢失'     => [
            '丢失包裹',
            '确认差异订单',
        ],
        '亚马逊—发件原因'     => [
            '卖家取消提货',
            '卖家推迟提货',
            '包裹未包装好',
            '联系不上提无人',
        ],
        '亚马逊—总站操作'     => [
            '包裹未到',
            '包裹回站',
            '去库房途中',
            '确认差异订单',
            '亚马逊投诉',
        ],
        '亚马逊—无法投递'     => [
            '恶意订单',
            '联系多天无果',
            '超区',
            '丢失包裹',
        ],
        '亚马逊—直送退货'     => [
            '寄件客户确认收货'
        ],
        '亚马逊—配送延迟'     => [
            '客户要求推迟(自提、延期)',
            '联系不上送无人',
            '客户要求更改地址',
            '仅面单备注只工作日送货',
            '仅面单备注双休日送货',
            '分拣错误',
            '无联系无派送',
            '异常天气',
            '非本站点派送范围',
        ],
        '其他'           => [
            '其他'
        ],
        '其他原因'         => [
            '自提件',
            '异常天气',
            '商品质量',
            '货款延迟申请',
            '其他',
        ],
        '发件原因'         => [
            '超区/无点',
            '面单不规范',
            '大头笔错写',
            '违禁品',
            '包装不规范',
            '地址不详',
            '电话错误',
            '未/少带派费',
        ],
        '国美拒收'         => [
            '网站降价',
            '配送超时',
            '货品错误',
            '商品存在质量问题',
            '超区无法配送',
            '网站信息与实物不符',
            '恶意订单',
        ],
        '客户原因'         => [
            '地址不详',
            '拒付代收货款',
            '电话无人接听',
            '客户要求重新派送',
            '查无此人',
            '恶意订单',
            '取消订单',
            '联系不上无人',
            '更改地址',
            '要求工作日派送',
            '要求周末派送',
            '要求推迟派送',
            '客户拒收',
            '拒付到付',
            '客户拒付货款',
            '拒付到付款',
        ],
        '投诉'           => [
            '其他',
            '未及时接单',
            '未及时取件',
            '延误',
            '遗失',
            '破损/短少',
            '多收费用',
            '未带POS机',
            '服务态度',
        ],
        '派件原因'         => [
            '超出配送能力',
            '派件延误',
            '快件丢失',
            '快件破损',
            '班车晚点',
        ],
        '留仓'           => [
            '错分'
        ],
        '留仓件'          => [
            '干线爆仓',
            '网点爆仓',
            '破损件',
            '违禁品',
            '地址不详',
            '错发件',
            '内件异常',
            '区域不明',
            '退件',
            '超区/无点',
            '双面单',
            '未赶上中转',
            '站点交货晚点',
            '站点提前离场',
            '站点未来取件',
            '站点整顿',
            '无中班',
            '大头笔错写',
            '资产盘点',
            '其他',
        ],
        '破损件'          => [
            '内件异常',
            '外包装破损'
        ],
        '站点原因'         => [
            '车辆偏小',
            '大货增加',
            '站点迟到',
            '无中班',
            '站点提前发车',
            '站点未来拉货',
        ],
        '网络班车'         => [
            '班车晚点',
            '操作延迟',
            '主干线爆仓',
        ],
        '超区/无点'        => [
            '超区',
            '无点转件',
        ],
        '错分'           => [
            '错分'
        ],
        '问题件'          => [
            '收件地址不详',
            '区域不明确',
            '面单脱落',
            '双面单',
            '大头笔错写',
            '违禁品',
            '破损件',
            '错发件',
            '无点转件',
            '站点车辆已装满',
            '贝贝熊退货',
        ],
    ];
}